package sk.ygor.raynor.client.test;

import com.google.gwt.json.client.JSONObject;
import sk.ygor.raynor.client.json.JSONProperty;

import java.util.Arrays;
import java.util.List;

public class RaynorTestClasses {

    public static JSONObject jsonPersonIgor() {
        return JSONBuilder.object(
                Person.class,
                JSONBuilder.prop("name", "Igor"),
                JSONBuilder.prop("age", 27)
        );
    }

    public static Person javaPersonIgor() {
        return new Person("Igor", 27);
    }

    public static class Parent {

        public String name;
        public List<Integer> luckyNumbers;
        public Child[] children;

        public static class Child {

            @JSONProperty(jsonPropertyName = "childName")
            public String name;
            public boolean fat;

            public Child() {
            }

            public Child(String name, boolean fat) {
                this.name = name;
                this.fat = fat;
            }

            @Override
            public String toString() {
                return "Child{" +
                        "name='" + name + '\'' +
                        ", fat=" + fat +
                        '}';
            }
        }

        @Override
        public String toString() {
            return "Parent{" +
                    "name='" + name + '\'' +
                    ", luckyNumbers=" + luckyNumbers +
                    ", children=" + Arrays.asList(children) +
                    '}';
        }
    }

    public static class Person {
        public String name;
        public Integer age;

        @SuppressWarnings({"UnusedDeclaration"})
        Person() {

        }

        Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public static DeepComparator<Person> deepComparator() {
            return new DeepComparator<Person>() {
                @Override
                public ComparablePart comparablePart(Person one, Person two) {
                    return new ComparableComposition(
                            new ComparableString(one.name, two.name),
                            new ComparableNumber(one.age, two.age)
                    );
                }
            };
        }

    }


    public static interface MaybePerson {

        public static class App {
            public static DeepComparator<MaybePerson> deepComparator() {
                return new DeepComparator<MaybePerson>() {
                    @Override
                    public ComparablePart comparablePart(MaybePerson one, MaybePerson two) {
                        return new ComparableHierarchy<MaybePerson>(MaybePerson.class, one, two,
                                new HierachyMember<SomePerson>(SomePerson.class, SomePerson.deepComparator()),
                                new HierachyMember<NoPerson>(NoPerson.class, NoPerson.deepComparator())
                        );
                    }
                };
            }
        }


    }

    public static class SomePerson implements MaybePerson {
        public Person person;

        @SuppressWarnings({"UnusedDeclaration"})
        public SomePerson() {
        }

        public SomePerson(Person person) {
            this.person = person;
        }

        public static DeepComparator<SomePerson> deepComparator() {
            return new DeepComparator<SomePerson>() {
                @Override
                public ComparablePart comparablePart(SomePerson one, SomePerson two) {
                    return new ComparableComposition(
                            Person.deepComparator().comparablePart(one.person, two.person)
                    );
                }
            };
        }

    }

    public static class NoPerson implements MaybePerson {
        public String reason;

        @SuppressWarnings({"UnusedDeclaration"})
        public NoPerson() {
        }

        public NoPerson(String reason) {
            this.reason = reason;
        }

        public static DeepComparator<NoPerson> deepComparator() {
            return new DeepComparator<NoPerson>() {
                @Override
                public ComparablePart comparablePart(NoPerson one, NoPerson two) {
                    return new ComparableString(one.reason, two.reason);
                }
            };
        }
    }

    public static class Review<T> {
        public String reviewOfItem;
        public T item;

        @SuppressWarnings({"UnusedDeclaration"})
        public Review() {
        }

        public Review(String reviewOfItem, T item) {
            this.reviewOfItem = reviewOfItem;
            this.item = item;
        }

        private static DeepComparator.ComparablePart reviewBase(Review one, Review two) {
            return new DeepComparator.ComparableString(one.reviewOfItem, two.reviewOfItem);
        }

        public static DeepComparator<Review<Person>> deepComparatorIfPerson() {
            return new DeepComparator<Review<Person>>() {
                @Override
                public ComparablePart comparablePart(Review<Person> one, Review<Person> two) {
                    return new ComparableComposition(
                            reviewBase(one, two),
                            Person.deepComparator().comparablePart(one.item, two.item)
                    );
                }
            };
        }
    }

    @SuppressWarnings({"UnusedDeclaration"})
    // oh dear :(
    public static interface Option<T> {

        public static class App {

            public static DeepComparator<Option<Integer>> deepComparatorIfInteger() {
                return new DeepComparator<Option<Integer>>() {
                    @Override
                    public ComparablePart comparablePart(Option one, Option two) {
                        return new ComparableHierarchy<Option>(Option.class, one, two,
                                new HierachyMember<Some>(Some.class, Some.deepComparatorIfInteger()),
                                new HierachyMember<None>(None.class, None.deepComparator())
                        );
                    }
                };
            }
        }
    }

    public static class Some<T> implements Option<T> {

        public T something;

        public Some() {
        }

        public Some(T something) {
            this.something = something;
        }

        public static DeepComparator<Some> deepComparatorIfInteger() {
            return new DeepComparator<Some>() {
                @Override
                public ComparablePart comparablePart(Some one, Some two) {
                    return new ComparableComposition(
                            new ComparableNumber((Integer) one.something, (Integer) two.something)
                    );
                }
            };
        }

    }

    public static class None<T> implements Option<T> { // it has to be typed, since Java has no variance

        public static DeepComparator<None> deepComparator() {
            return new DeepComparator<None>() {
                @Override
                public ComparablePart comparablePart(None one, None two) {
                    return new AlwaysEqual();
                }
            };
        }
    }

    public static class ClassWithNoArgConstructor {
        public ClassWithoutNoArgConstructor classWithoutNoArgConstructor;

        public ClassWithNoArgConstructor() {
        }
    }

    public static class ClassWithoutNoArgConstructor {
        public Integer i;

        public ClassWithoutNoArgConstructor(Integer i) {
            this.i = i;
        }
    }


}
